package com.ruyuan.little.project.rocketmq.api.pay.controller;

import com.ruyuan.little.project.common.dto.CommonResponse;
import com.ruyuan.little.project.common.enums.ErrorCodeEnum;
import com.ruyuan.little.project.common.enums.LittleProjectTypeEnum;
import com.ruyuan.little.project.redis.api.RedisApi;
import com.ruyuan.little.project.rocketmq.api.order.service.OrderService;
import com.ruyuan.little.project.rocketmq.api.pay.constants.PayTransactionStatusConstant;
import com.ruyuan.little.project.rocketmq.api.pay.dto.PayTransaction;
import com.ruyuan.little.project.rocketmq.api.pay.dto.QueryPayStatusResponse;
import com.ruyuan.little.project.rocketmq.api.pay.service.PayTransactionService;
import com.ruyuan.little.project.rocketmq.common.constants.PayTypeConstant;
import com.ruyuan.little.project.rocketmq.common.constants.RedisKeyConstant;
import com.ruyuan.little.project.rocketmq.common.utils.DateUtil;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author qiangjun@aliyun.com
 */
@RequestMapping("/api/pay")
@RestController
public class PayController {

    private static final Logger LOGGER = LoggerFactory.getLogger(PayController.class);

    @Resource
    private PayTransactionService payTransactionService;

    @Resource
    private OrderService orderService;

    /**
     * redis dubbo api接口
     */
    @Reference(version = "1.0.0", interfaceClass = RedisApi.class, cluster = "failfast", check = false)
    private RedisApi redisApi;


    /**
     * 微信支付回调
     * <p>
     * 分析下重复支付的问题：
     * 1. 客户在支付页面，重复点击了支付按钮，会发送多笔支付请求，这里的话在微信里会有微信的重复提醒标志，要么就是客户端做按钮的置灰操作——
     * 在请求没有响应时制成灰色；
     * 2. 微信支付回调的问题，有可能是触发了两次回调，因为网络延迟，就会在账户流水库中记录下多笔支付流水
     * <p>
     * 3. 这里的解决方式，我看了下，只解决了第2个场景下的支付重复问题。
     * 4. 那针对第1个场景来说的话，我的想法是可以在支付页面获取全局唯一的标记，在请求中带上这个标记作为是否重复支付的依据：
     * 4.1 这里有两个问题，1：就是全局唯一怎么实现，如何保证是全局唯一的；2：判别逻辑，可以使用redis.setNx来做判别
     *
     * @param queryPayStatusResponse
     * @return
     */
    @PostMapping("/wx/callback")
    public CommonResponse<Integer> wxCallback(QueryPayStatusResponse queryPayStatusResponse) {

        String orderNo = queryPayStatusResponse.getOrderNo();
        String phoneNumber = queryPayStatusResponse.getPhoneNumber();
        CommonResponse<Boolean> setNxResponse = redisApi.setnx(RedisKeyConstant.ORDER_DUPLICATION_KEY_PREFIX.concat(orderNo), orderNo, phoneNumber, LittleProjectTypeEnum.ROCKETMQ);
        if (Objects.equals(setNxResponse.getCode(), ErrorCodeEnum.FAIL.getCode())) {
            //
            LOGGER.info("pay order wx callback redis dubbo interface fail orderNo:{}",orderNo);
            return CommonResponse.fail(ErrorCodeEnum.FAIL);
        }

        if (Objects.equals(setNxResponse.getCode(), ErrorCodeEnum.SUCCESS.getCode()) &&
                Objects.equals(setNxResponse.getData(), Boolean.FALSE)) {
            LOGGER.info("duplicate pay order orderNo:{}",orderNo);
            return CommonResponse.success();
        }

        PayTransaction payTransaction = new PayTransaction();
        payTransaction.setOrderNo(orderNo);
        payTransaction.setUserPayAccount(queryPayStatusResponse.getUserPayAccount());
        payTransaction.setTransactionNumber(queryPayStatusResponse.getTransactionNumber());
        payTransaction.setFinishPayTime(DateUtil.format(queryPayStatusResponse.getFinishPayTime(), DateUtil.FULL_TIME_SPLIT_PATTERN));
        payTransaction.setResponseCode(queryPayStatusResponse.getResponseCode());
        payTransaction.setTransactionChannel(PayTypeConstant.WX);
        payTransaction.setPayableAmount(queryPayStatusResponse.getPayableAmount());
        Integer status = queryPayStatusResponse.getPayTransactionStatus();
        payTransaction.setStatus(status);

        if (!payTransactionService.save(payTransaction, phoneNumber)) {
            //等待微信重试
            return CommonResponse.fail();
        }

        Integer orderId = null;
        if (Objects.equals(status, PayTransactionStatusConstant.SUCCESS)) {
            try {
                orderId = orderService.informPayOrderSuccessed(orderNo, phoneNumber);
            } catch (Exception e) {
                redisApi.del(RedisKeyConstant.ORDER_DUPLICATION_KEY_PREFIX.concat(orderNo), phoneNumber, LittleProjectTypeEnum.ROCKETMQ);
            }
        }
        return CommonResponse.success(orderId);
    }


}